package com.gomro.galaxy.foundation.bi.engine.analysis;

import cn.gomro.cloud.core.common.utils.DateUtils;
import cn.gomro.cloud.core.common.utils.EncryptUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gomro.galaxy.core.batch.ElasticSearchClzItemReader;
import com.gomro.galaxy.core.batch.ElasticSearchClzItemWriter;
import com.gomro.galaxy.core.commons.elastic.ElasticSearchRest;
import com.gomro.galaxy.foundation.bi.domain.Constants;
import com.gomro.galaxy.foundation.bi.domain.event.SalesDataComparisonStatisticsVolumeEvent;
import com.gomro.galaxy.foundation.bi.domain.model.*;
import com.gomro.galaxy.foundation.bi.domain.model.analysis.SalesDataComparisonStatisticsVolume;
import com.gomro.galaxy.foundation.bi.engine.AnalysisLastTime;
import com.gomro.galaxy.foundation.bi.engine.model.AnalysisCache;
import com.gomro.galaxy.foundation.bi.engine.query.MemberQuery;
import com.gomro.galaxy.foundation.bi.engine.util.BoolQueryBuilders;
import com.gomro.galaxy.foundation.bi.engine.util.EngineUtils;
import com.gomro.galaxy.foundation.bi.exception.BiException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.batch.core.*;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.bus.BusProperties;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.NonNull;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
//销售数据对比统计导出
@Slf4j
@Configuration
public class SalesDataComparisonStatisticsVolumeJob {
    private static final String BiAnalysisLastName = Constants.BiDataMartIndexPrefix + AnalysisLastTime.TableName;
    private static final String BiWarehouseOrganizationName = Constants.BiWarehouseIndexPrefix + AcquireOrganization.TableName;
    private static final String BiWarehouseCustomerOrderName = Constants.BiWarehouseIndexPrefix + AcquireCustomerOrder.TableName;
    private static final String BiWarehouseVendorOrderName = Constants.BiWarehouseIndexPrefix + AcquireVendorOrder.TableName;
    private static final String BiWarehouseInquiryGoodsName = Constants.BiWarehouseIndexPrefix + AcquireInquiryGoods.TableName;
    private static final String BiWarehouseQuotationGoodsName = Constants.BiWarehouseIndexPrefix + AcquireQuotationGoods.TableName;
    private static final String BiWarehouseOrganizationInviteName = Constants.BiWarehouseIndexPrefix + AcquireOrganizationInviteCode.TableName;
    private static final String BiWarehouseOrderGoodsRefundName = Constants.BiWarehouseIndexPrefix + AcquireOrderGoodsRefund.TableName;
    private static final String BiWarehouseOrderGoodsName = Constants.BiWarehouseIndexPrefix + AcquireOrderGoods.TableName;
    private static final String BiWarehouseInquiryName = Constants.BiWarehouseIndexPrefix + AcquireInquiry.TableName;
    private static final String BiWarehouseMemberName = Constants.BiWarehouseIndexPrefix + AcquireMember.TableName;
    private static final String BiDataMartName = Constants.BiDataMartIndexPrefix + SalesDataComparisonStatisticsVolume.TableName;
    private static final String JobName = Constants.JobBeanNamePrefix + SalesDataComparisonStatisticsVolume.TableName;
    private static final String StepName1 = Constants.StepBeanNamePrefix + SalesDataComparisonStatisticsVolume.TableName + 1;
    private static final String StepName2 = Constants.StepBeanNamePrefix + SalesDataComparisonStatisticsVolume.TableName + 2;
    private static final String StepName3 = Constants.StepBeanNamePrefix + SalesDataComparisonStatisticsVolume.TableName + 3;
    private static final String StepName4 = Constants.StepBeanNamePrefix + SalesDataComparisonStatisticsVolume.TableName + 4;
    private static final String ReaderName1 = Constants.ReaderBeanNamePrefix + SalesDataComparisonStatisticsVolume.TableName + 1;
    private static final String ReaderName2 = Constants.ReaderBeanNamePrefix + SalesDataComparisonStatisticsVolume.TableName + 2;
    private static final String WriterName1 = Constants.WriterBeanNamePrefix + SalesDataComparisonStatisticsVolume.TableName + 1;
    private static final String WriterName2 = Constants.WriterBeanNamePrefix + SalesDataComparisonStatisticsVolume.TableName + 2;
    private static final String ProcessName1 = Constants.ProcessBeanNamePrefix + SalesDataComparisonStatisticsVolume.TableName + 1;
    private static final String ProcessName2 = Constants.ProcessBeanNamePrefix + SalesDataComparisonStatisticsVolume.TableName + 2;
    private static final String ProcessName3 = Constants.ProcessBeanNamePrefix + SalesDataComparisonStatisticsVolume.TableName + 3;
    private static final String ProcessName4 = Constants.ProcessBeanNamePrefix + SalesDataComparisonStatisticsVolume.TableName + 4;

    private ApplicationEventPublisher applicationEventPublisher;
    private BusProperties busProperties;
    private JobBuilderFactory jobBuilderFactory;
    private StepBuilderFactory stepBuilderFactory;
    private ElasticSearchRest rest;
    private RestHighLevelClient client;
    private ObjectMapper mapper;
    private AnalysisCache<SalesDataComparisonStatisticsVolume> cache = new AnalysisCache();

    public SalesDataComparisonStatisticsVolumeJob(ApplicationEventPublisher applicationEventPublisher, BusProperties busProperties, JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory, RestHighLevelClient client, ObjectMapper mapper) {
        this.applicationEventPublisher = applicationEventPublisher;
        this.busProperties = busProperties;
        this.jobBuilderFactory = jobBuilderFactory;
        this.stepBuilderFactory = stepBuilderFactory;
        this.client = client;
        this.mapper = mapper;
        this.rest = new ElasticSearchRest(client, mapper);
    }

    private QueryBuilder getOrganizationBuilder(Date start, Date end) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (Objects.nonNull(start)) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("time").gte(DateFormatUtils.format(start, "yyyy-MM-dd HH:mm:ss")));
        }
        if (Objects.nonNull(end)) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("time").lt(DateFormatUtils.format(end, "yyyy-MM-dd HH:mm:ss")));
        }
        boolQueryBuilder.must(QueryBuilders.termQuery("del", false));
        boolQueryBuilder.must(QueryBuilders.termQuery("architectureType", 2));
        boolQueryBuilder.must(QueryBuilders.existsQuery("businessMemberId"));
        boolQueryBuilder.mustNot(QueryBuilders.termQuery("businessMemberId", 0L));
        return boolQueryBuilder;
    }

    @Bean(ReaderName2)
    @StepScope
    public ItemReader<SalesDataComparisonStatisticsVolume> reader2() {
        return EngineUtils.createCacheReader(cache.getCache());
    }


    @Bean(ProcessName1)
    public ItemProcessor<AcquireOrganization, SalesDataComparisonStatisticsVolume> processor1() {
        return acquireOrganization -> {
            Date last = cache.getLast();

            LocalDateTime time = LocalDateTime.ofInstant(last.toInstant(), ZoneId.systemDefault());
            String id = EncryptUtils.MD5_32(DateUtils.dateToStr(last, DateUtils.FORMAT_PATTERN_DATE) + acquireOrganization.getBusinessMemberId());
            MemberQuery query = MemberQuery.builder().ids(Collections.singletonList(acquireOrganization.getBusinessMemberId())).build();
            ElasticSearchRest.SearchResultClz<AcquireMember> resultClz = rest.searchAsClz(BiWarehouseMemberName,
                    ElasticSearchRest.Page.of(1, 1), BoolQueryBuilders.member(query), null, null, AcquireMember.class);
            String businessName = "";
            if (Objects.nonNull(resultClz) && !CollectionUtils.isEmpty(resultClz.getData())) {
                businessName = resultClz.getData().get(0).getFullname();
            }
            return SalesDataComparisonStatisticsVolume.builder()
                    .id(id)
                    .organizationId(acquireOrganization.getId())
                    .businessName(businessName)
                    .businessId(acquireOrganization.getBusinessMemberId())
                    .statisticsTime(time.toLocalDate())
                    .customerActiveNumber(0.0)
                    .inquiryGoodsNumber(0.0)
                    .originalQuotationNumber(0.0)
                    .platformQuotationNumber(0.0)
                    .notQuotedGoodsNumber(0.0)
                    .originalTargetGoodsNumber(0.0)
                    .platfromTargetGoodsNumber(0.0)
                    .originalOrderGoodsNumber(0.0)
                    .platfromOrderGoodsNumber(0.0)
                    .orderNumber(0.0)
                    .originalOrderAmount(0.0)
                    .platfromOrderAmount(0.0)
                    .originalReturnAmount(0.0)
                    .platfromReturnAmount(0.0)
                    .inquiryGoodsNumberDifference(0.0)
                    .originalQuotationNumberDifference(0.0)
                    .platformQuotationNumberDifference(0.0)
                    .notQuotedGoodsNumberDifference(0.0)
                    .originalTargetGoodsNumberDifference(0.0)
                    .platfromTargetGoodsNumberDifference(0.0)
                    .originalOrderGoodsNumberDifference(0.0)
                    .platfromOrderGoodsNumberDifference(0.0)
                    .orderNumberDifference(0.0)
                    .originalOrderAmountDifference(0.0)
                    .platfromOrderAmountDifference(0.0)
                    .originalReturnAmountDifference(0.0)
                    .platfromReturnAmountDifference(0.0)
                    .build();
        };
    }
    @Bean(WriterName1)
    public ItemWriter<SalesDataComparisonStatisticsVolume> writer1() {
        return list -> list.forEach(e -> cache.getCache().put(e.getId(), e));
    }

    private JobExecutionListener jobExecutionListener = new JobExecutionListener() {

        @Override
        public void beforeJob(@NonNull JobExecution jobExecution) {

            ElasticSearchRest rest = new ElasticSearchRest(client, mapper);

            // 初始化数据索引
            //bi_data_mart_t_sales_data_comparison_statistics_volume
            //bi_data_mart_t_sales_data_comparison_statistics_volume
            if (!rest.indexExists(BiDataMartName)) {

                rest.indexCreate(BiDataMartName);
                rest.indexMappingPut(BiDataMartName, "analysis/" + BiDataMartName + ".json", true);
                rest.indexFlush(BiDataMartName, null, null);
            }

            // 初始化最后更新时间索引
            if (!rest.indexExists(BiAnalysisLastName)) {

                rest.indexCreate(BiAnalysisLastName);
                rest.indexMappingPut(BiAnalysisLastName, "analysis/" + BiAnalysisLastName + ".json", true);
                rest.indexFlush(BiAnalysisLastName, null, null);
            }
        }

        @Override
        public void afterJob(@NonNull JobExecution jobExecution) {
            log.debug("last time ---> {}", DateUtils.dateToStr(cache.getLast()));
            if (Objects.nonNull(cache.getCache())) {
                log.debug("cache size -> {}", cache.getCache().size());
                cache.getCache().clear();
            }
            // 回写最后更新时间
            if (jobExecution.getStatus() == BatchStatus.COMPLETED) {
                rest.documentCreate(BiAnalysisLastName, SalesDataComparisonStatisticsVolume.TableName, AnalysisLastTime.builder().id(SalesDataComparisonStatisticsVolume.TableName).last(cache.getLast()).build());
                applicationEventPublisher.publishEvent(new SalesDataComparisonStatisticsVolumeEvent(cache.getLast()));
            }
        }
    };

    /**
     * 询价查询构建
     *
     * @param start
     * @param end
     * @param orgId
     * @return
     */
    private QueryBuilder getInuqiryBuilder(Date start, Date end, Long orgId) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (Objects.nonNull(start)) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("time").gte(DateFormatUtils.format(start, "yyyy-MM-dd HH:mm:ss")));
        }
        if (Objects.nonNull(end)) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("time").lt(DateFormatUtils.format(end, "yyyy-MM-dd HH:mm:ss")));
        }
        boolQueryBuilder.must(QueryBuilders.termQuery("del", false));
        boolQueryBuilder.must(QueryBuilders.termsQuery("organizationId", Collections.singleton(orgId)));
        return boolQueryBuilder;
    }

    /**
     * 询价商品查询构建
     *
     * @param inquiryIdList
     * @return
     */
    private QueryBuilder getInuqiryGoodsBuilder(List<Long> inquiryIdList) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.termQuery("del", false));
        boolQueryBuilder.must(QueryBuilders.termsQuery("inquiryId", inquiryIdList));
        boolQueryBuilder.must(QueryBuilders.termsQuery("status", Arrays.asList(1, 2, 3, 4, 5)));
        return boolQueryBuilder;
    }

    /**
     * 报价商品查询构建
     *
     * @param inquiryGoodsIdList
     * @return
     */
    private QueryBuilder getQuotationGoods(Date start, Date end, List<Long> inquiryGoodsIdList) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.termQuery("del", false));
        if (Objects.nonNull(start)) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("time").gte(DateFormatUtils.format(start, "yyyy-MM-dd HH:mm:ss")));
        }
        if (Objects.nonNull(end)) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("time").lt(DateFormatUtils.format(end, "yyyy-MM-dd HH:mm:ss")));
        }
        boolQueryBuilder.must(QueryBuilders.termsQuery("inquiryGoodsId", inquiryGoodsIdList));
        boolQueryBuilder.must(QueryBuilders.termsQuery("status", Arrays.asList(1, 2, 3, 4, 5, 6, 7)));
        return boolQueryBuilder;
    }


    /**
     * 构建客户订单查询
     *
     * @param start
     * @param end
     * @param organizationId
     * @return
     */
    private QueryBuilder getCustomerOrderBuilder(Date start, Date end, Long organizationId) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (Objects.nonNull(start)) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("time").gte(DateFormatUtils.format(start, "yyyy-MM-dd HH:mm:ss")));
        }
        if (Objects.nonNull(end)) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("time").lt(DateFormatUtils.format(end, "yyyy-MM-dd HH:mm:ss")));
        }
        boolQueryBuilder.must(QueryBuilders.termQuery("del", false));
        boolQueryBuilder.must(QueryBuilders.termQuery("organizationId", organizationId));
        return boolQueryBuilder;
    }

    /**
     * 订单数据
     *
     * @return
     */
    @Bean(ProcessName3)
    public ItemProcessor<SalesDataComparisonStatisticsVolume, SalesDataComparisonStatisticsVolume> processor3() {
        return salesDataComparisonStatisticsVolume -> {
            // 订单商品数-原有供应商
            Integer originalOrderGoodsNumber = 0;
            //订单商品数-平台供应商
            Integer platfromOrderGoodsNumber = 0;
            // 订单数量
            Integer orderNumber = 0;
            //订单金额-原有供应商
            Double originalOrderAmount = 0.0;
            //订单金额-平台供应商
            Double platfromOrderAmount = 0.0;
            //查询客户的订单数量
            Long organizationId = salesDataComparisonStatisticsVolume.getOrganizationId();
            Date[] rangeDay = DateUtils.rangeDay(cache.getLast());
            QueryBuilder queryBuilder = getCustomerOrderBuilder(rangeDay[0], rangeDay[1], organizationId);
            //
            ElasticSearchRest.SearchResultClz<AcquireCustomerOrder> searchAsClz = rest.searchAsClz(BiWarehouseCustomerOrderName, null, queryBuilder, null, null, AcquireCustomerOrder.class);
            List<AcquireCustomerOrder> customerOrderList = new ArrayList<>();
            if (searchAsClz != null) {
                customerOrderList = searchAsClz.getData();
            }
            if (customerOrderList != null && !customerOrderList.isEmpty()) {
                orderNumber = customerOrderList.size();
                for (AcquireCustomerOrder customerOrder : customerOrderList) {
                    //查询供应商订单
                    BoolQueryBuilder vendorOrderBoolQueryBuilder = QueryBuilders.boolQuery();
                    vendorOrderBoolQueryBuilder.must(QueryBuilders.termQuery("del", false));
                    vendorOrderBoolQueryBuilder.must(QueryBuilders.termQuery("customerOrderId", customerOrder.getId()));
                    ElasticSearchRest.SearchResultClz<AcquireVendorOrder> vendorOrderSearchResultClz = rest.searchAsClz(BiWarehouseVendorOrderName, null, vendorOrderBoolQueryBuilder, null, null, AcquireVendorOrder.class);
                    //供应商订单集合
                    List<AcquireVendorOrder> acquireVendorOrderList = new ArrayList<>();
                    if (vendorOrderSearchResultClz != null) {
                        acquireVendorOrderList = vendorOrderSearchResultClz.getData();
                    }
                    if (acquireVendorOrderList != null && !acquireVendorOrderList.isEmpty()) {
                        for (AcquireVendorOrder acquireVendorOrder : acquireVendorOrderList) {
                            //查询供应商是否为该用户的邀请供应商
                            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
                            boolQueryBuilder.must(QueryBuilders.termQuery("vendorId", acquireVendorOrder.getVendorId()));
                            boolQueryBuilder.must(QueryBuilders.termQuery("customerId", organizationId));
                            ElasticSearchRest.SearchResultClz<AcquireOrganizationInviteCode> organizationInviteCodeSearchResultClz = rest.searchAsClz(BiWarehouseOrganizationInviteName, null, boolQueryBuilder, null, null, AcquireOrganizationInviteCode.class);
                            List<AcquireOrganizationInviteCode> acquireOrganizationInviteCodeList = new ArrayList<>();
                            if (organizationInviteCodeSearchResultClz != null) {
                                acquireOrganizationInviteCodeList = organizationInviteCodeSearchResultClz.getData();
                            }
                            //查询订单商品
                            BoolQueryBuilder orderGoodsBoolQueryBuilder = QueryBuilders.boolQuery();
                            orderGoodsBoolQueryBuilder.must(QueryBuilders.termQuery("del", false));
                            orderGoodsBoolQueryBuilder.must(QueryBuilders.termQuery("vendorOrderId", acquireVendorOrder.getId()));
                            ElasticSearchRest.SearchResultClz<AcquireOrderGoods> acquireOrderGoodsSearchResultClz = rest.searchAsClz(BiWarehouseOrderGoodsName, null, orderGoodsBoolQueryBuilder, null, null, AcquireOrderGoods.class);
                            List<AcquireOrderGoods> acquireOrderGoodsList = new ArrayList<>();
                            if (acquireOrderGoodsSearchResultClz != null) {
                                acquireOrderGoodsList = acquireOrderGoodsSearchResultClz.getData();
                            }
                            if (acquireOrderGoodsList != null && !acquireOrderGoodsList.isEmpty()) {
                                for (AcquireOrderGoods acquireOrderGoods : acquireOrderGoodsList) {
                                    if (acquireOrganizationInviteCodeList != null && !acquireOrganizationInviteCodeList.isEmpty()) {
                                        originalOrderGoodsNumber = originalOrderGoodsNumber + 1;
                                        originalOrderAmount = originalOrderAmount + acquireOrderGoods.getAmount();
                                    } else {
                                        platfromOrderGoodsNumber = platfromOrderGoodsNumber + 1;
                                        platfromOrderAmount = platfromOrderAmount + acquireOrderGoods.getAmount();
                                    }
                                }
                            }
                        }
                    }
                }
            }
            salesDataComparisonStatisticsVolume.setPlatfromOrderGoodsNumber(platfromOrderGoodsNumber.doubleValue());
            salesDataComparisonStatisticsVolume.setOrderNumber(orderNumber.doubleValue());
            salesDataComparisonStatisticsVolume.setOriginalOrderGoodsNumber(originalOrderGoodsNumber.doubleValue());
            salesDataComparisonStatisticsVolume.setPlatfromOrderAmount(platfromOrderAmount);
            salesDataComparisonStatisticsVolume.setOriginalOrderAmount(originalOrderAmount);
            return salesDataComparisonStatisticsVolume;
        };
    }

    /**
     * 构建退款查询
     *
     * @param start
     * @param end
     * @param orgId
     * @return
     */
    private QueryBuilder getRefundBuilder(Date start, Date end, Long orgId) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (Objects.nonNull(start)) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("time").gte(DateFormatUtils.format(start, "yyyy-MM-dd HH:mm:ss")));
        }
        if (Objects.nonNull(end)) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("time").lt(DateFormatUtils.format(end, "yyyy-MM-dd HH:mm:ss")));
        }
        boolQueryBuilder.must(QueryBuilders.termQuery("del", false));
        boolQueryBuilder.must(QueryBuilders.termQuery("customerId", orgId));
        return boolQueryBuilder;
    }


    /**
     * 退货部分
     *
     * @return
     */
    @Bean(ProcessName4)
    public ItemProcessor<SalesDataComparisonStatisticsVolume, SalesDataComparisonStatisticsVolume> processor4() {
        return SalesDataComparisonStatisticsVolume -> {
            //退货金额-原有供应商
            Double originalReturnAmount = 0.0;
            //退货金额-平台供应商
            Double platfromReturnAmount = 0.0;
            Long organizationId = SalesDataComparisonStatisticsVolume.getOrganizationId();
            Date[] rangeDay = DateUtils.rangeDay(cache.getLast());
            //获取该组织一天的订单商品
            QueryBuilder refundBuilder = getRefundBuilder(rangeDay[0], rangeDay[1], organizationId);
            ElasticSearchRest.SearchResultClz<AcquireOrderGoodsRefund> resultClz = rest.searchAsClz(BiWarehouseOrderGoodsRefundName, null, refundBuilder, null, null, AcquireOrderGoodsRefund.class);
            List<AcquireOrderGoodsRefund> refundList = new ArrayList<>();
            if (resultClz != null) {
                refundList = resultClz.getData();
            }
            if (refundList != null && !refundList.isEmpty()) {
                for (AcquireOrderGoodsRefund acquireOrderGoodsRefund : refundList) {
                    //查询供应商是否为该用户的邀请供应商
                    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
                    boolQueryBuilder.must(QueryBuilders.termQuery("vendorId", acquireOrderGoodsRefund.getVendorId()));
                    boolQueryBuilder.must(QueryBuilders.termQuery("customerId", organizationId));
                    ElasticSearchRest.SearchResultClz<AcquireOrganizationInviteCode> organizationInviteCodeSearchResultClz = rest.searchAsClz(BiWarehouseOrganizationInviteName, null, boolQueryBuilder, null, null, AcquireOrganizationInviteCode.class);
                    List<AcquireOrganizationInviteCode> acquireOrganizationInviteCodeList = new ArrayList<>();
                    if (organizationInviteCodeSearchResultClz != null) {
                        organizationInviteCodeSearchResultClz.getData();
                    }
                    if (acquireOrganizationInviteCodeList != null && !acquireOrganizationInviteCodeList.isEmpty()) {
                        originalReturnAmount = originalReturnAmount + acquireOrderGoodsRefund.getAmount();
                    } else {
                        platfromReturnAmount = platfromReturnAmount + acquireOrderGoodsRefund.getAmount();
                    }
                }
            }
            SalesDataComparisonStatisticsVolume.setOriginalReturnAmount(originalReturnAmount);
            SalesDataComparisonStatisticsVolume.setPlatfromReturnAmount(platfromReturnAmount);
            return SalesDataComparisonStatisticsVolume;
        };
    }

    @Bean(WriterName2)
    public ElasticSearchClzItemWriter<SalesDataComparisonStatisticsVolume> writer2() {

        return new ElasticSearchClzItemWriter<>(client, mapper, BiDataMartName);
    }

    /**
     * 询报价数据
     *
     * @return
     */
    @Bean(ProcessName2)
    public ItemProcessor<SalesDataComparisonStatisticsVolume, SalesDataComparisonStatisticsVolume> processor2() {
        return SalesDataComparisonStatisticsVolume -> {
            Long organizationId = SalesDataComparisonStatisticsVolume.getOrganizationId();
            Date[] rangeDay = DateUtils.rangeDay(cache.getLast());
            //询价单ID集合
            List<Long> inquiryIdList = new ArrayList<>();
            //询价商品数量
            Integer inquiryGoodsNumber = 0;
            //报价商品数量-未报价
            Integer notQuotedGoodsNumber = 0;
            //报价商品数量-平台供应商
            Integer platformQuotationNumber = 0;
            //报价商品数量-原有供应商
            Integer originalQuotationNumber = 0;
            // 定标商品数量-原有供应商
            Integer originalTargetGoodsNumber = 0;
            // 定标商品数量-平台供应商
            Integer platfromTargetGoodsNumber = 0;
            //获取该组织一天的询价商品
            QueryBuilder quotationBuilder = getInuqiryBuilder(rangeDay[0], rangeDay[1], organizationId);
            ElasticSearchRest.SearchResultClz<AcquireInquiry> acquireInquirySearchResultClz = rest.searchAsClz(BiWarehouseInquiryName, null, quotationBuilder, null, null, AcquireInquiry.class);
            if (acquireInquirySearchResultClz != null) {
                List<AcquireInquiry> inquiryList = acquireInquirySearchResultClz.getData();
                for (AcquireInquiry acquireInquiry : inquiryList) {
                    inquiryIdList.add(acquireInquiry.getId());
                }
            }
            //询价商品数
            if (inquiryIdList != null && !inquiryIdList.isEmpty()) {
                ElasticSearchRest.SearchResultClz<AcquireInquiryGoods> acquireInquiryGoodsSearchResultClz = rest.searchAsClz(BiWarehouseInquiryGoodsName, null, getInuqiryGoodsBuilder(inquiryIdList), null, null, AcquireInquiryGoods.class);
                //询价商品集合
                List<AcquireInquiryGoods> inquiryGoodsList = new ArrayList<>();
                if (acquireInquiryGoodsSearchResultClz != null) {
                    inquiryGoodsList = acquireInquiryGoodsSearchResultClz.getData();
                }
                if (inquiryGoodsList != null && !inquiryGoodsList.isEmpty()) {
                    //当天询价商品总数
                    inquiryGoodsNumber = inquiryGoodsList.size();
                }
            }
            //查询该客户当天截止的询价是否有报价
            BoolQueryBuilder expireEndInquiryBoolQueryBuilder = QueryBuilders.boolQuery();
            expireEndInquiryBoolQueryBuilder.must(QueryBuilders.termQuery("del", false));
            expireEndInquiryBoolQueryBuilder.must(QueryBuilders.rangeQuery("expire").gte(DateFormatUtils.format(rangeDay[0], "yyyy-MM-dd HH:mm:ss")));
            expireEndInquiryBoolQueryBuilder.must(QueryBuilders.rangeQuery("expire").lt(DateFormatUtils.format(rangeDay[1], "yyyy-MM-dd HH:mm:ss")));
            expireEndInquiryBoolQueryBuilder.must(QueryBuilders.termQuery("organizationId", organizationId));
            ElasticSearchRest.SearchResultClz<AcquireInquiry> expireEndInquiryClz = rest.searchAsClz(BiWarehouseInquiryName, null, expireEndInquiryBoolQueryBuilder, null, null, AcquireInquiry.class);
            List<AcquireInquiry> expireEndInquiryListAll = new ArrayList<>();
            if (expireEndInquiryClz != null) {
                expireEndInquiryListAll = expireEndInquiryClz.getData();
            }
            //该客当天截止的询价id
            List<Long> expireEndInquiryId = new ArrayList<>();

            if (expireEndInquiryListAll != null && !expireEndInquiryListAll.isEmpty()) {
                for (AcquireInquiry acquireInquiry : expireEndInquiryListAll) {
                    expireEndInquiryId.add(acquireInquiry.getId());
                }
            }
            //查询截止的询价商品
            ElasticSearchRest.SearchResultClz<AcquireInquiryGoods> expireEndInquiryGoodsClz = rest.searchAsClz(BiWarehouseInquiryGoodsName, null, getInuqiryGoodsBuilder(expireEndInquiryId), null, null, AcquireInquiryGoods.class);
            List<AcquireInquiryGoods> expireEndInquiryGoodsList = new ArrayList<>();
            if (expireEndInquiryGoodsClz != null) {
                expireEndInquiryGoodsList = expireEndInquiryGoodsClz.getData();
            }
            if (expireEndInquiryGoodsList != null && !expireEndInquiryGoodsList.isEmpty()) {
                for (AcquireInquiryGoods acquireInquiryGoods : expireEndInquiryGoodsList) {
                    if (acquireInquiryGoods.getQuoteCount() == 0) {
                        notQuotedGoodsNumber = notQuotedGoodsNumber + 1;
                    }
                }
            }

            //该客户的所有询价 （截止日期小于等于统计日）
            BoolQueryBuilder inquiryBoolQueryBuilder = QueryBuilders.boolQuery();
            inquiryBoolQueryBuilder.must(QueryBuilders.termQuery("del", false));
            inquiryBoolQueryBuilder.must(QueryBuilders.rangeQuery("expire").gte(DateFormatUtils.format(rangeDay[1], "yyyy-MM-dd HH:mm:ss")));
            inquiryBoolQueryBuilder.must(QueryBuilders.rangeQuery("time").lt(DateFormatUtils.format(rangeDay[1], "yyyy-MM-dd HH:mm:ss")));
            inquiryBoolQueryBuilder.must(QueryBuilders.termQuery("organizationId", organizationId));
            ElasticSearchRest.SearchResultClz<AcquireInquiry> inquiryAll = rest.searchAsClz(BiWarehouseInquiryName, null, inquiryBoolQueryBuilder, null, null, AcquireInquiry.class);
            List<AcquireInquiry> inquiryListAll = new ArrayList<>();
            if (inquiryAll != null) {
                inquiryListAll = inquiryAll.getData();
            }
            //该客户所有询价id
            List<Long> inqiryIdAll = new ArrayList<>();

            if (inquiryListAll != null && !inquiryListAll.isEmpty()) {
                for (AcquireInquiry acquireInquiry : inquiryListAll) {
                    inqiryIdAll.add(acquireInquiry.getId());
                }
            }
            //该客户inqiryIdAll下的所有询价商品
            ElasticSearchRest.SearchResultClz<AcquireInquiryGoods> acquireInquiryGoodsSearchResultClz = rest.searchAsClz(BiWarehouseInquiryGoodsName, null, getInuqiryGoodsBuilder(inqiryIdAll), null, null, AcquireInquiryGoods.class);
            List<AcquireInquiryGoods> inqiryGoodsAll = new ArrayList<>();
            //该客户inqiryIdAll下的所有询价商品ID
            List<Long> inquiryGoodsIdAll = new ArrayList<>();
            if (acquireInquiryGoodsSearchResultClz != null) {
                inqiryGoodsAll = acquireInquiryGoodsSearchResultClz.getData();
            }
            if (inqiryGoodsAll != null && !inqiryGoodsAll.isEmpty()) {
                for (AcquireInquiryGoods acquireInquiryGoods : inqiryGoodsAll) {
                    inquiryGoodsIdAll.add(acquireInquiryGoods.getId());
                }
            }
            //当天的报价商品
            ElasticSearchRest.SearchResultClz<AcquireQuotationGoods> quotationGoodsSearchResultClz = rest.searchAsClz(BiWarehouseQuotationGoodsName, null,
                    getQuotationGoods(rangeDay[0], rangeDay[1], inquiryGoodsIdAll), null, null, AcquireQuotationGoods.class);
            List<AcquireQuotationGoods> quotationGoodsList = new ArrayList<>();
            if (quotationGoodsSearchResultClz != null) {
                quotationGoodsList = quotationGoodsSearchResultClz.getData();
            }
            if (quotationGoodsList != null && !quotationGoodsList.isEmpty()) {
                for (AcquireQuotationGoods acquireQuotationGoods : quotationGoodsList) {
                    //查询供应商是否为该用户的邀请供应商
                    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
                    boolQueryBuilder.must(QueryBuilders.termQuery("vendorId", acquireQuotationGoods.getVendorOrganizationId()));
                    boolQueryBuilder.must(QueryBuilders.termQuery("customerId", organizationId));
                    ElasticSearchRest.SearchResultClz<AcquireOrganizationInviteCode> organizationInviteCodeSearchResultClz = rest.searchAsClz(BiWarehouseOrganizationInviteName, null, boolQueryBuilder, null, null, AcquireOrganizationInviteCode.class);
                    List<AcquireOrganizationInviteCode> acquireOrganizationInviteCodeList = new ArrayList<>();
                    if (organizationInviteCodeSearchResultClz != null) {
                        acquireOrganizationInviteCodeList = organizationInviteCodeSearchResultClz.getData();
                    }
                    //没查到或者查到的集合没有该客户的ID，平台报价数加1，否则邀请供应商+1
                    if (acquireOrganizationInviteCodeList != null && !acquireOrganizationInviteCodeList.isEmpty()) {
                        originalQuotationNumber = originalQuotationNumber + 1;

                    } else {
                        platformQuotationNumber = platformQuotationNumber + 1;
                    }
                    //定标信息,5代表已定标
                    if (acquireQuotationGoods.getStatus() == 5) {

                        if (acquireOrganizationInviteCodeList != null && !acquireOrganizationInviteCodeList.isEmpty()) {
                            originalTargetGoodsNumber = originalTargetGoodsNumber + 1;

                        } else {
                            platformQuotationNumber = platformQuotationNumber + 1;
                        }
                    }
                }

            }

            SalesDataComparisonStatisticsVolume.setInquiryGoodsNumber(inquiryGoodsNumber.doubleValue());
            SalesDataComparisonStatisticsVolume.setOriginalQuotationNumber(originalQuotationNumber.doubleValue());
            SalesDataComparisonStatisticsVolume.setPlatformQuotationNumber(platformQuotationNumber.doubleValue());
            SalesDataComparisonStatisticsVolume.setNotQuotedGoodsNumber(notQuotedGoodsNumber.doubleValue());
            SalesDataComparisonStatisticsVolume.setOriginalTargetGoodsNumber(originalTargetGoodsNumber.doubleValue());
            SalesDataComparisonStatisticsVolume.setPlatfromTargetGoodsNumber(platfromTargetGoodsNumber.doubleValue());
            return SalesDataComparisonStatisticsVolume;
        };


    }

    @Bean(ReaderName1)
    @StepScope
    public ElasticSearchClzItemReader<AcquireOrganization> reader1() {

        // 获取最后更新时间
        AnalysisLastTime analysisLastTime = rest.documentGet(BiAnalysisLastName, SalesDataComparisonStatisticsVolume.TableName, AnalysisLastTime.class);
        Date start;
        if (analysisLastTime != null && analysisLastTime.getLast() != null) {
            start = DateUtils.addDays(analysisLastTime.getLast(), 1);
        } else {
            ElasticSearchRest.SearchResultClz<AcquireOrganization> data = rest.searchAsClz(BiWarehouseOrganizationName, ElasticSearchRest.Page.of(1, 1), null, Collections.singleton(SortBuilders.fieldSort("time").order(SortOrder.ASC)), null, AcquireOrganization.class);
            if (Objects.isNull(data) || CollectionUtils.isEmpty(data.getData())) {
                throw new BiException("analysisLastTime init error");
            }
            start = Date.from(data.getData().get(0).getTime().atZone(ZoneId.systemDefault()).toInstant());
        }
        Date[] rangeDay = DateUtils.rangeDay(start);
        cache.setLast(start);
        log.debug("查询日期 -> {}", DateUtils.dateToStr(rangeDay[1], DateUtils.FORMAT_PATTERN_DATE));

        //初始化缓存, 不能并行任务
        if (Objects.isNull(cache.getCache())) {
            cache.setCache(new HashMap<>());
        }

        ElasticSearchClzItemReader<AcquireOrganization> reader = new ElasticSearchClzItemReader<>(client, mapper, BiWarehouseOrganizationName,
                100, getOrganizationBuilder(null, rangeDay[1]), Collections.singleton(SortBuilders.fieldSort("id").order(SortOrder.ASC)), AcquireOrganization.class);
        reader.setName(ReaderName1);
        return reader;
    }


    @Bean(JobName)
    public Job job(@Qualifier(StepName1) Step step1, @Qualifier(StepName2) Step step2, @Qualifier(StepName3) Step step3, @Qualifier(StepName4) Step step4) {

        return jobBuilderFactory.get(JobName)
                .incrementer(new RunIdIncrementer())
                .start(step1)
                .next(step2)
                .next(step3)
                .next(step4)
                .listener(jobExecutionListener)
                .build();
    }

    @Bean(StepName1)
    public Step step1() {

        return stepBuilderFactory.get(StepName1)
                .<AcquireOrganization, SalesDataComparisonStatisticsVolume>chunk(100)
                .reader(reader1())
                .processor(processor1())
                .writer(writer1())
                .build();
    }

    @Bean(StepName2)
    public Step step2() {

        return stepBuilderFactory.get(StepName2)
                .<SalesDataComparisonStatisticsVolume, SalesDataComparisonStatisticsVolume>chunk(100)
                .reader(reader2())
                .processor(processor2())
                .writer(writer1())
                .build();
    }

    @Bean(StepName3)
    public Step step3() {

        return stepBuilderFactory.get(StepName2)
                .<SalesDataComparisonStatisticsVolume, SalesDataComparisonStatisticsVolume>chunk(100)
                .reader(reader2())
                .processor(processor3())
                .writer(writer1())
                .build();
    }

    @Bean(StepName4)
    public Step step4() {

        return stepBuilderFactory.get(StepName2)
                .<SalesDataComparisonStatisticsVolume, SalesDataComparisonStatisticsVolume>chunk(100)
                .reader(reader2())
                .processor(processor4())
                .writer(writer2())
                .build();
    }

}
